﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.ServiceModel;
using System.Text;
using NUnit.Framework;
using Universe.WCF.Behaviors.WcfStreaming;

namespace WcfStreamTests
{
    [TestFixture]
    public class BasicTest
    {
        private ServiceHost _host;
        
        [SetUp]
        public void SetUp()
        {
            _host = TestClient.ConfigureService();
        }

        [Test]
        public void Test_Fail_With_Default_Configuration()
        {
            Guid token = Guid.NewGuid();
            using (var factory = TestClient.ConfigureChannel())
            {
                factory.Open(TimeSpan.FromSeconds(20));
                var proxy = factory.CreateChannel();

                int arg = 9999999;

                bool isCommunicationOK;
                try
                {
                    var stream = new HashReaderStream(proxy.GetMyStream(token, arg, true), MD5.Create(), 128);
                    byte[] content;
                    string hash;
                    stream.ReadToEnd(out content, out hash, 1024);
                    isCommunicationOK = true;
                    Assert.Fail("Server should fail");
                }
                catch(CommunicationException ex)
                {
                    isCommunicationOK = false;
                }

                Assert.IsFalse(isCommunicationOK, "CommunicationException is expected");
                using(var otherFactory = TestClient.ConfigureChannel())
                {
                    otherFactory.Open(TimeSpan.FromSeconds(10));
                    var otherProxy = otherFactory.CreateChannel();

                    // First status should be 'Failed'
                    {
                        var status = otherProxy.GetMyStreamStatus(token);
                        Assert.IsNotNull(status, "Status is expected");
                        Assert.IsTrue(status.State == ResponseState.Failed, "On Fail Status Should Be Failed");
                        Assert.IsNotNull(status.Exception, "On Fail Exception Is Expected");
                        Assert.AreEqual(MyService.MyExceptionMessage, status.Exception.Message, "Exception Message is available on client");
                        Assert.AreEqual(typeof(ArgumentException).FullName, status.Exception.Type, "Exception Type is available on client");
                        Assert.IsNull(status.Hash, "On Fail Hash should be null");
                    }

                    // Next status request is NULL
                    {
                        var status = otherProxy.GetMyStreamStatus(token);
                        Assert.IsNull(status, "Next status request returns null");
                    }

                }




            }
        }
        
        [Test]
        public void Test_Success_With_Default_Configuration()
        {
            Guid token = Guid.NewGuid();
            using(var factory = TestClient.ConfigureChannel())
            {
                factory.Open(TimeSpan.FromSeconds(20));
                var proxy = factory.CreateChannel();

                int arg = 9999999;
                var stream = new HashReaderStream(proxy.GetMyStream(token, arg, false), MD5.Create(), 128);
                Assert.IsTrue(stream.CanRead, "Proxy Stream is Readable");

                byte[] content;
                string hash;
                stream.ReadToEnd(out content, out hash, 128);
                Assert.AreEqual(arg, content.Length, "WCF stream size should be {0}", arg);

                var len = proxy.GetMyStreamLength(token);
                Assert.AreEqual(arg, len, "On Complete Stream Length should be {0}", arg);

                // First status request is OK
                {
                    var status = proxy.GetMyStreamStatus(token);
                    Assert.IsNotNull(status);
                    Assert.IsTrue(status.State == ResponseState.Success, "On Success Status Should Be Success");
                    Assert.IsNull(status.Exception, "On Success Exception Should Be NULL");
                    Assert.AreEqual(status.Hash, hash, "Hash '" + hash + "' is expected");
                }

                // Next status request is NULL
                {
                    var status = proxy.GetMyStreamStatus(token);
                    Assert.IsNull(status, "Next status request returns null");
                }

            }
        }

        [TearDown]
        public void TearDown()
        {
            _host.Close();
        }
    }
}
